#region File Description
//-----------------------------------------------------------------------------
// ModelViewerControl.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion

#region Using Statements
using System;
using System.Linq;
using System.Diagnostics;
using System.Windows.Forms;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using TriExporterNET.Engine;
using Microsoft.Xna.Framework.Content;
#endregion

namespace Microsoft.Windows.Forms.Xna
{
    /// <summary>
    /// Example control inherits from GraphicsDeviceControl, and displays
    /// a spinning 3D model. The main form class is responsible for loading
    /// the model: this control just displays it.
    /// </summary>
    class ModelViewerControl : GraphicsDeviceControl
    {
        /// <summary>
        /// Gets or sets the current model.
        /// </summary>
        public EVEMesh Model
        {
            get { return model; }

            set
            {
                model = value;

                if (model != null)
                {
                    smth = 0;
                    //MeasureModel();
                }
            }
        }

        EVEMesh model;
        Effect SkySphereEffect;
        Model SkySphere;
        TriExporterNET.BasicEffect basicEffect;
        TriExporterNET.EnvironmentMapEffect evnEffect;

        Vector3 modelCenter;
        float modelRadius;
        SpriteFont font;

        // Timer controls the rotation speed.
        Stopwatch timer;
        class MyMgr : ContentManager
        {
            public MyMgr(IServiceProvider provider):base(provider)
            {

            }
            protected override System.IO.Stream OpenStream(string assetName)
            {
                return new System.IO.MemoryStream((byte[])TriExporterNET.Properties.Resources.ResourceManager.GetObject(assetName));
            }
        }
        /// <summary>
        /// Initializes the control.
        /// </summary>
        protected override void Initialize()
        {
            // Start the animation timer.
            timer = Stopwatch.StartNew();
            ContentManager mgr = new MyMgr(Services);//, @"");
            font = mgr.Load<SpriteFont>("SpriteFont1");
            SkySphereEffect = mgr.Load<Effect>("SkySphere");
            SkySphere = mgr.Load<Model>("SphereHighPoly");
            evnEffect = new TriExporterNET.EnvironmentMapEffect(GraphicsDevice);
            //evnEffect.EnvironmentMap =  cube =  
                //mgr.Load<TextureCube>("g09_cube");//angelice_cube");
                
            // Hook the idle event to constantly redraw our animation.
            basicEffect = new TriExporterNET.BasicEffect(GraphicsDevice);
            spriteBatch = new SpriteBatch(GraphicsDevice);
            Application.Idle += delegate { Invalidate(); };


            // Set the Skysphere Effect to each part of the Skysphere model
            foreach (ModelMesh mesh in SkySphere.Meshes)
            {
                foreach (ModelMeshPart part in mesh.MeshParts)
                {
                    part.Effect = SkySphereEffect;
                }
            }
        }



        float smth = 0;
        TextureCube cube;
        int frameRate = 0;
        int frameCounter = 0;
        TimeSpan elapsedTime = TimeSpan.Zero;
        TimeSpan lastTime = TimeSpan.Zero;
        SpriteBatch spriteBatch;
        bool rotationenabled = true;
        float rotation = 0;
        /// <summary>
        /// Draws the control.
        /// </summary>
        protected override void Draw()
        {
            // Clear to the default control background color.
            //Color backColor = new Color(BackColor.R, BackColor.G, BackColor.B);

            //GraphicsDevice.Clear(backColor);
            //var 
            frameCounter++;
            string fps = string.Format("fps: {0}", frameRate);
            var elaps = timer.Elapsed;
            elapsedTime += elaps - lastTime;

            if (elapsedTime > TimeSpan.FromSeconds(1))
            {
                elapsedTime -= TimeSpan.FromSeconds(1);
                frameRate = frameCounter;
                frameCounter = 0;
            }
            lastTime = elaps;


            if (model != null)
            {
                // Compute camera matrices.
                if(rotationenabled)
                rotation = (float)elaps.TotalSeconds / 3f;
                modelCenter = model.modelCenter;
                modelRadius = model.modelRadius;
                Vector3 eyePosition = modelCenter;
                eyePosition.Z +=  (modelRadius  + smth )* 2 ;
                eyePosition.Y += modelRadius + smth;

                float aspectRatio = GraphicsDevice.Viewport.AspectRatio;

                float nearClip = modelRadius / 100;
                float farClip = modelRadius * 100;

                Matrix world = Matrix.CreateRotationY(rotation);// *new Matrix(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
                Matrix view = Matrix.CreateLookAt(eyePosition, modelCenter, Vector3.Up);
                Matrix projection = Matrix.CreatePerspectiveFieldOfView(1, aspectRatio,
                                                                    nearClip, farClip);

                SkySphereEffect.Parameters["ViewMatrix"].SetValue(world * view);
                SkySphereEffect.Parameters["ProjectionMatrix"].SetValue(projection);
                SkySphereEffect.Parameters["SkyboxTexture"].SetValue(EVEMesh.cube);
                foreach (ModelMesh mesh in SkySphere.Meshes)
                {
                    mesh.Draw();
                }

                GraphicsDevice.BlendState = BlendState.Opaque;
                GraphicsDevice.DepthStencilState = DepthStencilState.Default;
                GraphicsDevice.RasterizerState = RasterizerState.CullNone;




                GraphicsDevice.SetVertexBuffer(model.vertexBuffer);
                GraphicsDevice.Indices = Model.IndexBuffer;
                foreach (var part in Model.meshParts.Where(x => !x.IsTransparent))
                {
                    evnEffect.World = world;
                    evnEffect.View = view;
                    evnEffect.Projection = projection;
                    evnEffect.EnvironmentMap = EVEMesh.cube;
                    
                    if (part.DiffuseMap != null)
                    {
                        //evnEffect.Alpha = 1f;
                        evnEffect.FresnelFactor = 8f;
                        evnEffect.Texture = (Texture2D)Model.textures[part.DiffuseMap];
                        if (part.GlowNormalSpecularMap != null)
                        evnEffect.NormalMap =  (Texture2D)Model.textures[part.GlowNormalSpecularMap];
                        if (part.Pgs != null)
                        {
                            evnEffect.Pgs = (Texture2D)Model.textures[part.Pgs];
                            evnEffect.CurrentTechnique = evnEffect.Techniques[1];
                        }
                        else
                            evnEffect.CurrentTechnique = evnEffect.Techniques[0];
                        evnEffect.DiffuseColor = new Vector3(part.MaterialDiffuseColor[0] * 1.5f,
                            part.MaterialDiffuseColor[1] * 1.5f,
                            part.MaterialDiffuseColor[2] *1.5f);
                        evnEffect.EmissiveColor = new Vector3(part.GlowColor[0],
                            part.GlowColor[1],
                            part.GlowColor[2]);
                    }
                    else
                    {
                        evnEffect.DiffuseColor = new Vector3(1, 1, 1);
                    }
                    evnEffect.EnableDefaultLighting();
                    foreach (EffectPass pass in evnEffect.CurrentTechnique.Passes)
                    {
                        pass.Apply();

                        GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList,
                                             0, 0, Model.VertexCount,
                                             part.TriangleFirst, part.TriangleCount);
                    }
                }

                GraphicsDevice.BlendState = BlendState.AlphaBlend;
                
                foreach (var part in Model.meshParts.Where(x => x.IsTransparent))
                {

                    evnEffect.World = world;
                    evnEffect.View = view;
                    evnEffect.Projection = projection;
                    evnEffect.EnvironmentMap = EVEMesh.cube;
                   // GraphicsDevice.Indices = part.IndexBuffer;
                    if (part.DiffuseMap != null)
                    {
                            evnEffect.Alpha = .9f;
                            evnEffect.FresnelFactor = .8f;
                            evnEffect.Texture = (Texture2D)Model.textures[part.DiffuseMap];
                        evnEffect.DiffuseColor = new Vector3(part.MaterialDiffuseColor[0],
                            part.MaterialDiffuseColor[1],
                            part.MaterialDiffuseColor[2]);
                        if (part.Pgs != null)
                        {
                            evnEffect.Pgs = (Texture2D)Model.textures[part.Pgs];
                            evnEffect.CurrentTechnique = evnEffect.Techniques[1];
                        }
                        else
                            evnEffect.CurrentTechnique = evnEffect.Techniques[0];
                        evnEffect.EmissiveColor = new Vector3(0,0, 0);
                    }
                    else
                    {
                        evnEffect.DiffuseColor = new Vector3(1, 1, 1);
                    }
                    evnEffect.EnableDefaultLighting();
                    foreach (EffectPass pass in evnEffect.CurrentTechnique.Passes)
                    {
                        pass.Apply();

                        GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList,
                                             0, 0, Model.VertexCount,
                                             part.TriangleFirst, part.TriangleCount);
                                             //0, part.TriangleCount);
                    }
                }
            }

            spriteBatch.Begin();
            spriteBatch.DrawString(font, fps, new Vector2(5, 5), Color.Black);
            spriteBatch.DrawString(font, fps, new Vector2(4, 4), Color.White);
            spriteBatch.End();
        }

        public void KeyDown1(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Down:
                    smth += modelRadius / 100f;
                    break;
                case Keys.Up:
                    smth -= modelRadius / 100f;
                    break;
                case Keys.Space:
                    rotationenabled = !rotationenabled;
                    break;
                case Keys.Left:
                    if (!rotationenabled)
                        rotation += 0.15f;
                    break;
                case Keys.Right:
                    if (!rotationenabled)
                        rotation -= 0.15f;
                    break;
                default:
                    break;
            }
        }

    }
}


